﻿using System;
using GeoAPI.Geometries;
using NetTopologySuite.Algorithm;

namespace NetTopologySuite.Noding.Snapround
{
	public class HotPixel
	{
		public HotPixel(Coordinate pt, double scaleFactor, LineIntersector li)
		{
			this._originalPt = pt;
			this._pt = pt;
			this._scaleFactor = scaleFactor;
			this._li = li;
			if (scaleFactor <= 0.0)
			{
				throw new ArgumentException("Scale factor must be non-zero");
			}
			if (scaleFactor != 1.0)
			{
				this._pt = new Coordinate(this.Scale(pt.X), this.Scale(pt.Y));
				this._p0Scaled = new Coordinate();
				this._p1Scaled = new Coordinate();
			}
			this.InitCorners(this._pt);
		}

		public Coordinate Coordinate
		{
			get
			{
				return this._originalPt;
			}
		}

		public Envelope GetSafeEnvelope()
		{
			if (this._safeEnv == null)
			{
				double num = 0.75 / this._scaleFactor;
				this._safeEnv = new Envelope(this._originalPt.X - num, this._originalPt.X + num, this._originalPt.Y - num, this._originalPt.Y + num);
			}
			return this._safeEnv;
		}

		private void InitCorners(Coordinate pt)
		{
			this._minx = pt.X - 0.5;
			this._maxx = pt.X + 0.5;
			this._miny = pt.Y - 0.5;
			this._maxy = pt.Y + 0.5;
			this._corner[0] = new Coordinate(this._maxx, this._maxy);
			this._corner[1] = new Coordinate(this._minx, this._maxy);
			this._corner[2] = new Coordinate(this._minx, this._miny);
			this._corner[3] = new Coordinate(this._maxx, this._miny);
		}

		private double Scale(double val)
		{
			return System.Math.Round(val * this._scaleFactor);
		}

		public bool Intersects(Coordinate p0, Coordinate p1)
		{
			if (this._scaleFactor == 1.0)
			{
				return this.IntersectsScaled(p0, p1);
			}
			this.CopyScaled(p0, this._p0Scaled);
			this.CopyScaled(p1, this._p1Scaled);
			return this.IntersectsScaled(this._p0Scaled, this._p1Scaled);
		}

		private void CopyScaled(Coordinate p, Coordinate pScaled)
		{
			pScaled.X = this.Scale(p.X);
			pScaled.Y = this.Scale(p.Y);
		}

		public bool IntersectsScaled(Coordinate p0, Coordinate p1)
		{
			double num = System.Math.Min(p0.X, p1.X);
			double num2 = System.Math.Max(p0.X, p1.X);
			double num3 = System.Math.Min(p0.Y, p1.Y);
			double num4 = System.Math.Max(p0.Y, p1.Y);
			return this._maxx >= num && this._minx <= num2 && this._maxy >= num3 && this._miny <= num4 && this.IntersectsToleranceSquare(p0, p1);
		}

		private bool IntersectsToleranceSquare(Coordinate p0, Coordinate p1)
		{
			bool flag = false;
			bool flag2 = false;
			this._li.ComputeIntersection(p0, p1, this._corner[0], this._corner[1]);
			if (this._li.IsProper)
			{
				return true;
			}
			this._li.ComputeIntersection(p0, p1, this._corner[1], this._corner[2]);
			if (this._li.IsProper)
			{
				return true;
			}
			if (this._li.HasIntersection)
			{
				flag = true;
			}
			this._li.ComputeIntersection(p0, p1, this._corner[2], this._corner[3]);
			if (this._li.IsProper)
			{
				return true;
			}
			if (this._li.HasIntersection)
			{
				flag2 = true;
			}
			this._li.ComputeIntersection(p0, p1, this._corner[3], this._corner[0]);
			return this._li.IsProper || (flag && flag2) || p0.Equals(this._pt) || p1.Equals(this._pt);
		}

		private bool IntersectsPixelClosure(Coordinate p0, Coordinate p1)
		{
			this._li.ComputeIntersection(p0, p1, this._corner[0], this._corner[1]);
			if (this._li.HasIntersection)
			{
				return true;
			}
			this._li.ComputeIntersection(p0, p1, this._corner[1], this._corner[2]);
			if (this._li.HasIntersection)
			{
				return true;
			}
			this._li.ComputeIntersection(p0, p1, this._corner[2], this._corner[3]);
			if (this._li.HasIntersection)
			{
				return true;
			}
			this._li.ComputeIntersection(p0, p1, this._corner[3], this._corner[0]);
			return this._li.HasIntersection;
		}

		public bool AddSnappedNode(INodableSegmentString segStr, int segIndex)
		{
			Coordinate[] coordinates = segStr.Coordinates;
			Coordinate p = coordinates[segIndex];
			Coordinate p2 = coordinates[segIndex + 1];
			if (this.Intersects(p, p2))
			{
				segStr.AddIntersection(this.Coordinate, segIndex);
				return true;
			}
			return false;
		}

		private readonly LineIntersector _li;

		private readonly Coordinate _pt;

		private readonly Coordinate _originalPt;

		private readonly Coordinate _p0Scaled;

		private readonly Coordinate _p1Scaled;

		private readonly double _scaleFactor;

		private double _minx;

		private double _maxx;

		private double _miny;

		private double _maxy;

		private readonly Coordinate[] _corner = new Coordinate[4];

		private Envelope _safeEnv;

		private const double SafeEnvelopeExpansionFactor = 0.75;
	}
}
